iT邦幫忙

2022 iThome 鐵人賽

DAY 12
0
Modern Web

前端技能樹的十萬個為什麼系列 第 12

Day 12 - 為什麼要用 Day.js

  • 分享至 

  • xImage
  •  

前言

如果今天網站需要處理日期&時間的計算、顯示、比較等行為,你會想到什麼工具呢?

許多人看到「日期」、「時間」就直覺想到的是 new Date(),畢竟這是原生的 API 嘛~但如果真的試著用原生的 Date 來操作,不免在很多時候會感受到無力與困惑,往往還是會需要透過第三方的 library 來協助。

而今天的主角 Day.js 就會是這方面的佼佼者!其他當然還有許多 libraries(如: LuxonDate-fns),讓我們來看看為什麼只要牽涉到時間,大家就轉而選擇第三方套件吧!

先想一下

  • Day.js 是在什麼樣的時代誕生的?
  • Day.js 怎麼解決問題?
  • Day.js 的優缺點是什麼?
  • Day.js 適合什麼情境?

Day.js 是在什麼樣的時代誕生的?

如果考慮使用原生的 Date 來處理日期與時間,面對官方琳瑯滿目的 API,初學者可能會有以下疑惑:

.getYear().getFullYear().getUTCFullYear() 都是「年」差在哪?
為什麼 .getMonth() 的一月是從 0 開始?
.toISOString().toUTCString().toLocaleString() 要顯示時間該用哪個?

另外,可能有些邏輯要用很複雜的方式做到,比如:

  • 計算日期加減
  • 比較日期先後
  • 顯示特定日期格式
  • 轉換時區

以及,因為 Date 的 API 具有 mutable 的特性,也就是說會直接修改到 Date 物件本身,而不是回傳一個全新的物件。因此對於一些 set 系列的 API,這個特性如果沒有特別注意,就很容易產生 bug。

Day.js 怎麼解決問題?

Day.js 是一個專門用來處理日期與時間的 library,官方網站直接寫:

Fast 2kB alternative to Moment.js with the same modern API

裡面提到了另一個 library 叫做 Moment.js,可以簡單理解為「mutable 版本的 Day.js」,也算是上個時代用來處理日期時間的熱門 library,但因為目前已經算是 deprecated 狀態,因此這邊就不特別說明它了。

Day.js 主打的是以下特點:

  • 2kB:為了不要跟原生 Date 比起來造成太大負擔,走一個輕薄短小的風格,可以引入基本核心的功能,額外的功能再搭配 plugins 處理。
  • Simple:API 簡單易懂,比起原生 Date 還要好懂,且與 Moment.js 的 API 極為類似,要轉移可說是非常輕鬆。
  • Immutable:這點非常重要,每一個 API 操作都回傳全新的 Day.js 物件,可以避免潛在的 bug,增進 debug 的效率。
  • I18n:顯示日期與時間的方面,可以選用多國語,呈現上面更多元,而且沒用到的就不會占空間,不會增加太多額外的負擔。

Day.js 在做的事情,其實很像 jQuery 的概念,也就是說「原生的操作很困難,所以引用簡單易懂的 library 來處理」,因此 Day.js 提供了一系列方便的 API,比如:

// 顯示指定日期格式
dayjs('2022-09-25').format('YYYY/MM/DD') // 2022/09/25

// 加減日期
dayjs('2022-09-25').add(3, 'day').format('YYYY/MM/DD') // 2022/09/28

// 比較日期
dayjs('2022-09-25').isBefore(dayjs('2022-09-26')) // true

Immutable

比如 Moment.js,因為 API 屬於 mutable 特性,會遇到這樣的問題:

const today = moment('2022-09-25');
const tomorrow = today.add(1, 'day');

// today 居然也變成 26 號了!
console.log(today.format('YYYY-MM-DD')); // 2022-09-26
console.log(tomorrow.format('YYYY-MM-DD')); // 2022-09-26

往往需要透過手動 .clone() 來避免,但這其實在效能方便是比較不好的:

const today = moment('2022-09-25');
const tomorrow = today.clone().add(1, 'day');

// today 正常了! 但 .clone() 操作是比較昂貴的
console.log(today.format('YYYY-MM-DD')); // 2022-09-25
console.log(tomorrow.format('YYYY-MM-DD')); // 2022-09-26

因此 Day.js 將 API 改為 immutable,可以省掉不少麻煩(而且跟 Moment.js 的語法幾乎沒變):

const today = dayjs('2022-09-25');
const tomorrow = today.add(1, 'day');

console.log(today.format('YYYY-MM-DD')); // 2022-09-25
console.log(tomorrow.format('YYYY-MM-DD')); // 2022-09-26

Day.js 的優缺點是什麼?

優點

  • 易懂好用的 API,因為都是返回 Day.js 物件,因此可以串接(chainable)
  • package 輕薄短小,基本功能不佔太多空間
  • Immutable,每個 API 都回傳全新的 Day.js 物件,而非修改物件本身,避免 side effect 造成 bug

缺點

從 Moment.js 這種 mutable API library 轉過來 Day.js,基本上可說是無痛轉移了,只有部分 plugin 需要手動 extend,以及需要轉換成 immutable API 的思維,其實是找不太到明顯的缺點。

Day.js 適合什麼情境?

由於是專門針對特定需求(日期與時間操作),因此這類 library 很明確,有需要就用XD

不像 jQuery 在當時是一黨獨大,Day.js 之外仍有很多可替換的操作日期 library,雖然各有不同特色,但目的是一致的,都是為了減少操作日期時間的困難度,讓使用者更方便,並寫出更好讀的 code。

其他選項還有像是 LuxonDate-fns

結語

心智圖放大版

由於公司的專案就是從使用 Moment.js 開始,我先是嘗到了一波甜頭

啊~原來操作日期可以這麼簡單!

但隨著商業需求日趨複雜,開始遇到了一些 bug,找到最後才發現原來是因為 Moment.js API 帶有 mutable 的特性,如果沒有特別注意就會寫出有 bug 的程式。

於是到下一個新專案後開始轉成 Day.js,狀況才好轉不少,比較少遇到意料之外的狀況。

參考資料

How to work with date in plain JavaScript
老项目使用 dayjs 替代 moment 的注意事项


上一篇
Day 11 - 為什麼要用 Yup
下一篇
Day 13 - 為什麼要用 Virtualized List
系列文
前端技能樹的十萬個為什麼30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言